﻿using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using TransformerManager.Shared.Helper.HttpParams;
using TransformerManager.WPF.Common.Helper.Events;
using TransformerManager.WPF.Common.Http.Service;
using TransformerManager.WPF.Common.Utils;

namespace TransformerManager.WPF.Main.ViewModels
{
    public class AuthWindowViewModel : BindableBase
    {
        private readonly IEventAggregator _eventAggregator;
        private readonly IConfiguration _configuration;
        private readonly IAccountService _accountService;

        private const string cacheFileName = "cache.json"; // 缓存密码文件名
        private const string key = "ae125efkk4#54ee@f444ferfkny6oxi8"; // 32位加密key

        public AuthWindowViewModel(
            IEventAggregator eventAggregator,
            IAccountService accountService,
            IConfiguration configuration)
        {
            _eventAggregator = eventAggregator;
            _configuration = configuration;
            _accountService = accountService;

            _registerParams.UserName = System.Environment.UserName;

            InitCmd();

            LoadPasswordFromLocal(_configuration);
        }


        #region Command

        public DelegateCommand LoginCmd { private set; get; }

        public DelegateCommand RegisterCmd { private set; get; }

        public DelegateCommand ToRegisterPageCmd { private set; get; }

        public DelegateCommand ToLoginPageCmd { private set; get; }

        public DelegateCommand ExitCmd { private set; get; }

        #endregion


        #region 方法的定义

        private bool _isRememberMe = false;
        public bool IsRememberMe
        {
            get { return _isRememberMe; }

            set { SetProperty(ref _isRememberMe, value); }
        }

        private string _logo = "&#xe675;";
        public string Logo
        {
            set
            {
                _logo = value;
                RaisePropertyChanged();
            }
            get
            {
                return _logo;
            }
        }

        private LoginParams _loginParams = new LoginParams();

        public LoginParams LoginParams
        {
            get { return _loginParams; }

            set { SetProperty(ref _loginParams, value); }
        }

        private RegisterParams _registerParams = new RegisterParams();

        public RegisterParams RegisterParams
        {
            get { return _registerParams; }

            set { SetProperty(ref _registerParams, value); }
        }

        private Visibility _loadingVisibility = Visibility.Collapsed;
        public Visibility LoadingVisibility
        {
            set { SetProperty(ref _loadingVisibility, value); }

            get
            {
                return _loadingVisibility;
            }
        }

        private bool _isLoginGridEnabled = true;
        public bool IsLoginGridEnabled
        {
            set { SetProperty(ref _isLoginGridEnabled, value); }

            get
            {
                return _isLoginGridEnabled;
            }
        }

        private Visibility _loginGridVisibility = Visibility.Visible;
        public Visibility LoginGridVisibility
        {
            set { SetProperty(ref _loginGridVisibility, value); }

            get
            {
                return _loginGridVisibility;
            }
        }

        private bool _isRegisterGridEnabled = true;
        public bool IsRegisterGridEnabled
        {
            set { SetProperty(ref _isRegisterGridEnabled, value); }

            get
            {
                return _isRegisterGridEnabled;
            }
        }

        private Visibility _RegisterGridVisibility = Visibility.Collapsed;
        public Visibility RegisterGridVisibility
        {
            set { SetProperty(ref _RegisterGridVisibility, value); }

            get
            {
                return _RegisterGridVisibility;
            }
        }

        #endregion


        #region 函数的定义

        private void InitCmd()
        {
            ExitCmd = new DelegateCommand(() =>
            {
                Environment.Exit(0);
            });

            LoginCmd = new DelegateCommand(async () =>
            {
                LoadingVisibility = Visibility.Visible;
                IsLoginGridEnabled = false;

                await OnLogin();

                LoadingVisibility = Visibility.Collapsed;
                IsLoginGridEnabled = true;

            });

            RegisterCmd = new DelegateCommand(async () =>
            {
                LoadingVisibility = Visibility.Visible;
                IsRegisterGridEnabled = false;

                await OnRegister();

                LoadingVisibility = Visibility.Collapsed;
                IsRegisterGridEnabled = true;

            });

            ToRegisterPageCmd = new DelegateCommand(() =>
            {
                LoadingVisibility = Visibility.Collapsed;
                LoginGridVisibility = Visibility.Collapsed;
                RegisterGridVisibility = Visibility.Visible;
                IsRegisterGridEnabled = true;
            });

            ToLoginPageCmd = new DelegateCommand(() =>
            {
                LoadingVisibility = Visibility.Collapsed;
                RegisterGridVisibility = Visibility.Collapsed;
                LoginGridVisibility = Visibility.Visible;
                IsLoginGridEnabled = true;
            });
        }

        private async Task OnLogin()
        {
            try 
            {
                // 请求登录
                var tokenResult = await _accountService.LoginAsync(_loginParams);

                if (tokenResult == null || string.IsNullOrEmpty(tokenResult.AccessToken))
                {
                    return;
                }

                AccountInfo.UserName = _loginParams.UserName;
                AccountInfo.AccessToken = tokenResult.AccessToken;

                // 如果界面勾选了记录密码, 则对密码加密缓存
                if (_isRememberMe)
                {
                    SavePasswordToLocal(_configuration, _loginParams.Password);
                }

                // 登录成功后通知登录窗口关闭
                _eventAggregator.GetEvent<LoginEvent>().Publish(true);
            }
            catch(Exception ex)
            {
                HandyControl.Controls.MessageBox.Show(
                    $"错误信息:{ex.Message}, 登录失败!",
                    "错误",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
        }

        private async Task OnRegister()
        {
            try
            {
                await _accountService.RegisterAsync(_registerParams);
            }
            catch (Exception ex)
            {
                HandyControl.Controls.MessageBox.Show(
                    $"错误信息:{ex.Message}, 注册失败!",
                    "错误",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
        }

        private async void LoadPasswordFromLocal(IConfiguration configuration)
        {
            string cacheFullPath = $@"{ configuration["Cache:Path"]}\{cacheFileName}";

            try
            {
                // 创建
                if (!File.Exists(cacheFullPath))
                {

                    FileStream fs = new FileStream(cacheFullPath, FileMode.CreateNew, FileAccess.ReadWrite);
                    using (StreamWriter sw = new StreamWriter(fs))
                    {
                        JObject jsonObj = new JObject
                        {
                            ["IsRememberMe"] = false,
                            ["UserName"] = _loginParams.UserName,
                            ["Ciphertext"] = string.Empty
                        };
                        string jsonStrContent = JsonConvert.SerializeObject(jsonObj);
                        await sw.WriteAsync(jsonStrContent);
                        await sw.FlushAsync();
                        sw.Close();
                    }
                    fs.Close();
                    File.SetAttributes(cacheFullPath, FileAttributes.Hidden);
                }

                // 读取
                using (StreamReader sr = File.OpenText(cacheFullPath))
                {
                    string jsonStrContent = sr.ReadToEnd();
                    var jsonObj = JsonConvert.DeserializeObject(jsonStrContent) as JObject;
                    var userName = jsonObj["UserName"].Value<string>();
                    if (!string.IsNullOrEmpty(userName))
                    {
                        _isRememberMe = jsonObj["IsRememberMe"].Value<bool>();
                        _loginParams.UserName = userName;
                        _loginParams.Password = _isRememberMe ?
                            DecryptPassword(jsonObj["Ciphertext"].Value<string>(), key) : string.Empty;
                    }
                    else
                    {
                        _isRememberMe = jsonObj["IsRememberMe"].Value<bool>();
                        _loginParams.UserName = string.Empty;
                        _loginParams.Password = string.Empty;
                    }

                    sr.Close();
                }
            }
            catch (Exception ex)
            {
                HandyControl.Controls.MessageBox.Show(
                    $"错误信息:{ex.Message}, 无法正常加载相关配置文件, 请检查程序后重试!",
                    "错误",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
                if (File.Exists(cacheFullPath))
                {
                    File.Delete(cacheFullPath);
                }
            }
        }

        private async void SavePasswordToLocal(IConfiguration configuration, string plaintext)
        {
            string cacheFullPath = $@"{ configuration["Cache:Path"]}\{cacheFileName}";

            try
            {
                FileStream fs = new FileStream(cacheFullPath, FileMode.Open, FileAccess.ReadWrite);
                using (StreamReader sr = new StreamReader(fs))
                {
                    string jsonStrContent = await sr.ReadToEndAsync();
                    JObject jsonObj = JsonConvert.DeserializeObject(jsonStrContent) as JObject;
                    jsonObj["IsRememberMe"] = _isRememberMe;
                    jsonObj["UserName"] = _loginParams.UserName;
                    jsonObj["Ciphertext"] = EncryptPassword(plaintext, key);
                    jsonStrContent = JsonConvert.SerializeObject(jsonObj);
                    fs.Seek(0, SeekOrigin.Begin);
                    fs.SetLength(0);
                    using StreamWriter sw = new StreamWriter(fs);
                    await sw.WriteAsync(jsonStrContent);
                    await sw.FlushAsync();
                    sw.Close();
                }
                fs.Close();
            }
            catch (Exception ex)
            {
                HandyControl.Controls.MessageBox.Show(
                    $"错误信息:{ex.Message}, 本地设置缓存失败!",
                    "错误",
                    MessageBoxButton.OK,
                    MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="plaintext">明文</param>
        /// <param name="key">密码key</param>
        /// <returns>返回加密后的字符串</returns>
        private string EncryptPassword(string plaintext, string key)
        {
            if (string.IsNullOrEmpty(plaintext)) return string.Empty;
            Byte[] toEncryptArray = Encoding.UTF8.GetBytes(plaintext);

            System.Security.Cryptography.RijndaelManaged rm =
                new System.Security.Cryptography.RijndaelManaged
                {
                    Key = Encoding.UTF8.GetBytes(key),
                    Mode = System.Security.Cryptography.CipherMode.ECB,
                    Padding = System.Security.Cryptography.PaddingMode.PKCS7
                };

            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateEncryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="ciphertext">密文</param>
        /// <param name="key">密码key</param>
        /// <returns>返回解密后的字符串</returns>
        private string DecryptPassword(string ciphertext, string key)
        {
            if (string.IsNullOrEmpty(ciphertext)) return string.Empty;
            Byte[] toEncryptArray = Convert.FromBase64String(ciphertext);

            System.Security.Cryptography.RijndaelManaged rm =
                new System.Security.Cryptography.RijndaelManaged
                {
                    Key = Encoding.UTF8.GetBytes(key),
                    Mode = System.Security.Cryptography.CipherMode.ECB,
                    Padding = System.Security.Cryptography.PaddingMode.PKCS7
                };

            System.Security.Cryptography.ICryptoTransform cTransform = rm.CreateDecryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);

            return Encoding.UTF8.GetString(resultArray);
        }

        #endregion

    }
}
